package com.googlecode.dgwt.client.dojo.reflect;

import java.util.List;
import java.util.Map;

import com.googlecode.dgwt.client.dojo.core.JsArray;
import com.googlecode.dgwt.client.dojo.core.JsMap;
import com.googlecode.dgwt.client.dojo.core.JsObject;
import com.googlecode.dgwt.client.dojo.core.NativeWrapper;

/**
 * @author wellsantos@wellsantos.com
 * @since 0.01
 */
public abstract class BeanInfo<Bean> implements NativeWrapper {
    
    public abstract String getName();

    public abstract Class<Bean> getType();
    
    public abstract List<BeanMethod<Bean>> getMethods();

    public abstract Map<String,BeanField<Bean>> getFields();
 
    public abstract List<BeanMethod<Bean>> getConstructors();

    
    public BeanMethod<Bean> findConstructor(Class<?> ...paramClasses) {
        MainLoop:
        for (BeanMethod<Bean> method : getConstructors()) {
            if (paramClasses.length != method.getParams().size()){
                continue;
            }
            int index=0;
            for (Class<?> type : paramClasses) {
                if (type != null && type != method.getParams().get(index).getType()) {
                    continue MainLoop;
                }
            }
            return method;
        }
        return null;
    }    
    
    
    public BeanMethod<Bean> findMethod(String methodName, Class<?> ...paramClasses) {
        MainLoop:
        for (BeanMethod<Bean> method : getMethods()) {
            if (method.getName().equals(methodName)) {
                if (paramClasses.length != method.getParams().size()){
                    continue;
                }
                int index=0;
                for (Class<?> type : paramClasses) {
                    if (type != null && type != method.getParams().get(index).getType()) {
                        continue MainLoop;
                    }
                }
                return method;
            }
        }
        return null;
    }

    
    public BeanMethod<Bean> findGetter(String beanMethodName) {
        BeanField<Bean> info = getFields().get(beanMethodName);
        return info == null ? null : info.getGetter();
    }
    
    
    public BeanMethod<Bean> findSetter(String beanMethodName) {
        BeanField<Bean> info = getFields().get(beanMethodName);
        return info == null ? null : info.getSetter();
    }


    public JsObject toJavaScript() {
        JsMap<JsObject> methodMap = JsMap.create();
        for (String key : getFields().keySet()) {
            methodMap.set(key, getFields().get(key).toJavaScript());
        }
        
        JsArray<JsObject> methodArray = JsArray.create();
        int index = 0;
        
        for (BeanMethod<Bean> info : getMethods()) {
            methodArray.set(index++, info.toJavaScript());
        }
        
        JsMap<Object> map = JsMap.create();
        map.set("fields", methodMap);
        map.set("methods", methodArray);
        map.set("type", getType());
        map.set("name", getName());
        return map;
    }

}
